package netty.coffee;

import com.google.gson.Gson;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.util.Map;
import java.util.concurrent.*;

@Sharable
class CoffeeDataHandler extends ChannelInboundHandlerAdapter {

    private static final Logger LOG = LoggerFactory.getLogger(CoffeeDataHandler.class);
    /**
     * 保存所有的连接信息
     */
    private Map<String, Channel> channelMap = new ConcurrentHashMap<>();
    private Map<String, ScheduledFuture> futureMap = new ConcurrentHashMap<>();
    ScheduledExecutorService schedule = Executors.newScheduledThreadPool(4);

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        LOG.info("NettyIceHandler channelActive");
        InetSocketAddress ipSocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String mClientIp = ipSocket.getAddress().getHostAddress();
        if (null == mClientIp || "".equals(mClientIp.trim())) {
            return;
        }
        channelMap.put(mClientIp, ctx.channel());
        ScheduledFuture scheduledFuture = schedule.scheduleAtFixedRate(
                new CoffeeTask(ctx.channel()), 5, 10, TimeUnit.SECONDS);

        futureMap.put(ctx.channel().id().asLongText(), scheduledFuture);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        LOG.info("NettyIceHandler channelInactive");
        InetSocketAddress ipSocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String mClientIp = ipSocket.getAddress().getHostAddress();
        if (null == mClientIp || mClientIp.trim().equals("")) {
            return;
        }
        channelMap.remove(mClientIp, ctx.channel());
        futureMap.remove(ctx.channel().id().asLongText()).cancel(false);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        try {
            LOG.info("NettyIceHandler channelRead0 msg:" + new Gson().toJson(msg));
        } finally {
            // 必须释放msg数据
            ReferenceCountUtil.release(msg);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        LOG.info("NettyIceHandler exceptionCaught", cause);
        if (ctx != null && ctx.channel() != null) {
            ctx.channel().close();
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        LOG.info("NettyIceHandler userEventTriggered");
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.READER_IDLE) {
                LOG.warn("channel read idle, we will close channel");
                Channel channel = ctx.channel();
                if (null != channel) {
                    channel.disconnect();
                    channel.close();
                    channel = null;
                }
            }
        }
    }
}
